/******************************************************************************
 *版权
 *  $Id$
 *
 *  Copyright (C) 2006-2012  Florian Pose, Ingenieurgemeinschaft IgH
 *
 *  This file is part of the IgH EtherCAT master userspace library.
 *	该文件是IgH EtherCAT主站用户空间库的一部分。
 *  The IgH EtherCAT master userspace library is free software; you can
 *  redistribute it and/or modify it under the terms of the GNU Lesser General
 *  Public License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *	IgH EtherCAT主站用户空间库是免费软件；在GNU协议下你可以修改它或重新发布它。
 *  The IgH EtherCAT master userspace library is distributed in the hope that
 *  it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with the IgH EtherCAT master userspace library. If not, see
 *  <http://www.gnu.org/licenses/>.
 *
 *  ---
 *
 *  The license mentioned above concerns the source code only. Using the
 *  EtherCAT technology and brand is only permitted in compliance with the
 *  industrial property and similar rights of Beckhoff Automation GmbH.
 *
 *****************************************************************************/

/** \file
 *
 * EtherCAT master application interface.
 *
 * \defgroup ApplicationInterface EtherCAT Application Interface
 *
 * EtherCAT interface for realtime applications. This interface is designed
 * for realtime modules that want to use EtherCAT. There are functions to
 * request a master, to map process data, to communicate with slaves via CoE
 * and to configure and activate the bus.
 *
 * Changes in version 1.5.2:
 *
 * - Added redundancy_active flag to ec_domain_state_t.
 * - Added ecrt_master_link_state() method and ec_master_link_state_t to query
 *   the state of a redundant link.
 * - Added the EC_HAVE_REDUNDANCY define, to check, if the interface contains
 *   redundancy features.
 * - Added ecrt_sdo_request_index() to change SDO index and subindex after
 *   handler creation.
 * - Added interface for retrieving CoE emergency messages, i. e.
 *   ecrt_slave_config_emerg_size(), ecrt_slave_config_emerg_pop(),
 *   ecrt_slave_config_emerg_clear(), ecrt_slave_config_emerg_overruns() and
 *   the defines EC_HAVE_EMERGENCY and EC_COE_EMERGENCY_MSG_SIZE.
 * - Added interface for direct EtherCAT register access: Added data type
 *   ec_reg_request_t and methods ecrt_slave_config_create_reg_request(),
 *   ecrt_reg_request_data(), ecrt_reg_request_state(),
 *   ecrt_reg_request_write(), ecrt_reg_request_read() and the feature flag
 *   EC_HAVE_REG_ACCESS.
 * - Added method to select the reference clock,
 *   ecrt_master_select_reference_clock() and the feature flag
 *   EC_HAVE_SELECT_REF_CLOCK to check, if the method is available.
 * - Added method to get the reference clock time,
 *   ecrt_master_reference_clock_time() and the feature flag
 *   EC_HAVE_REF_CLOCK_TIME to have the possibility to synchronize the master
 *   clock to the reference clock.
 * - Changed the data types of the shift times in ecrt_slave_config_dc() to
 *   int32_t to correctly display negative shift times.
 * - Added ecrt_slave_config_reg_pdo_entry_pos() and the feature flag
 *   EC_HAVE_REG_BY_POS for registering PDO entries with non-unique indices
 *   via their positions in the mapping.
 *
 * Changes in version 1.5:
 *
 * - Added the distributed clocks feature and the respective method
 *   ecrt_slave_config_dc() to configure a slave for cyclic operation, and
 *   ecrt_master_application_time(), ecrt_master_sync_reference_clock() and
 *   ecrt_master_sync_slave_clocks() for offset and drift compensation. The
 *   EC_TIMEVAL2NANO() macro can be used for epoch time conversion, while the
 *   ecrt_master_sync_monitor_queue() and ecrt_master_sync_monitor_process()
 *   methods can be used to monitor the synchrony.
 * - Improved the callback mechanism. ecrt_master_callbacks() now takes two
 *   callback functions for sending and receiving datagrams.
 *   ecrt_master_send_ext() is used to execute the sending of non-application
 *   datagrams.
 * - Added watchdog configuration (method ecrt_slave_config_watchdog(),
 *   #ec_watchdog_mode_t, \a watchdog_mode parameter in ec_sync_info_t and
 *   ecrt_slave_config_sync_manager()).
 * - Added ecrt_slave_config_complete_sdo() method to download an SDO during
 *   configuration via CompleteAccess.
 * - Added ecrt_master_deactivate() to remove the bus configuration.
 * - Added ecrt_open_master() and ecrt_master_reserve() separation for
 *   userspace.
 * - Added bus information interface (methods ecrt_master(),
 *   ecrt_master_get_slave(), ecrt_master_get_sync_manager(),
 *   ecrt_master_get_pdo() and ecrt_master_get_pdo_entry()) to get information
 *   about the currently connected slaves and the PDO entries provided.
 * - Added ecrt_master_sdo_download(), ecrt_master_sdo_download_complete() and
 *   ecrt_master_sdo_upload() methods to let an application transfer SDOs
 *   before activating the master.
 * - Changed the meaning of the negative return values of
 *   ecrt_slave_config_reg_pdo_entry() and ecrt_slave_config_sdo*().
 * - Implemented the Vendor-specific over EtherCAT mailbox protocol. See
 *   ecrt_slave_config_create_voe_handler().
 * - Renamed ec_sdo_request_state_t to #ec_request_state_t, because it is also
 *   used by VoE handlers.
 * - Removed 'const' from argument of ecrt_sdo_request_state(), because the
 *   userspace library has to modify object internals.
 * - Added 64-bit data access macros.
 * - Added ecrt_slave_config_idn() method for storing SoE IDN configurations,
 *   and ecrt_master_read_idn() and ecrt_master_write_idn() to read/write IDNs
 *   ad-hoc via the user-space library.
 * - Added ecrt_master_reset() to initiate retrying to configure slaves.
 *
 * @{
 */

/*****************************************************************************/

#ifndef __ECRT_H__
#define __ECRT_H__

#ifdef __KERNEL__
#include <asm/byteorder.h>
#include <linux/types.h>
#include <linux/time.h>
#else
#include <stdlib.h> // for size_t
#include <stdint.h>
#include <sys/time.h> // for struct timeval
#endif

/******************************************************************************
 *01 Global definitions 全局定义
 *****************************************************************************/

/** EtherCAT realtime interface major version number.
    EhherCAT 实时接口主版本号
 */
#define ECRT_VER_MAJOR 1

/** EtherCAT realtime interface minor version number.
    EhherCAT 实时接口次版本号
 */
#define ECRT_VER_MINOR 5

/** EtherCAT realtime interface version word generator.
    EhherCAT 实时接口版本号生成
 */
#define ECRT_VERSION(a, b) (((a) << 8) + (b))

/** EtherCAT realtime interface version word.
    EhherCAT 实时接口版本号
 */
#define ECRT_VERSION_MAGIC ECRT_VERSION(ECRT_VER_MAJOR, ECRT_VER_MINOR)

/******************************************************************************
 *02 Feature flags 特性标志
 *****************************************************************************/

/** Defined, if the redundancy features are available.
 *定义，如果冗余特性可用。
 * I. e. if the \a redundancy_active flag in ec_domain_state_t and the
 * ecrt_master_link_state() method are available.
 */
#define EC_HAVE_REDUNDANCY

/** Defined, if the CoE emergency ring feature is available.
 *定义，如果CoE紧急环特性可用。
 * I. e. if the ecrt_slave_config_emerg_*() methods are available.
 */
#define EC_HAVE_EMERGENCY

/** Defined, if the register access interface is available.
 *定义，如果寄存器访问接口可用。
 * I. e. if the methods ecrt_slave_config_create_reg_request(),
 * ecrt_reg_request_data(), ecrt_reg_request_state(), ecrt_reg_request_write()
 * and ecrt_reg_request_read() are available.
 */
#define EC_HAVE_REG_ACCESS

/** Defined if the method ecrt_master_select_reference_clock() is available.
 *当方法ecrt主选择参考时钟()可用时定义。*/
#define EC_HAVE_SELECT_REF_CLOCK

/** Defined if the method ecrt_master_reference_clock_time() is available.
 *当方法ecrt主参考时钟time()可用时定义*/
#define EC_HAVE_REF_CLOCK_TIME

/** Defined if the method ecrt_slave_config_reg_pdo_entry_pos() is available.
 *定义方法ecrt从配置reg pdo入口pos()可用*/
#define EC_HAVE_REG_BY_POS

/** Defined if the method ecrt_master_sync_reference_clock_to() is available.
 *当方法ecrt主同步参考时钟to()可用时定义。*/
#define EC_HAVE_SYNC_TO

/*****************************************************************************/

/** End of list marker.
 *列表结束标记。
 * This can be used with ecrt_slave_config_pdos().
 *这可以与ecrt_slave_config_pdos()一起使用。*/
#define EC_END ~0U

/** Maximum number of sync managers per slave.
*每个从服务器的最大同步管理器数量。
 */
#define EC_MAX_SYNC_MANAGERS 16

/** Maximum string length.
 *最大字符串长度。
 * Used in ec_slave_info_t.
 * 在ec_slave_info_t里面使用
 */
#define EC_MAX_STRING_LENGTH 64

/** Maximum number of slave ports.最大从端口数。 */
#define EC_MAX_PORTS 4

/** Timeval to nanoseconds conversion.
 *里氏到纳秒的转换。
 * This macro converts a Unix epoch time to EtherCAT DC time.
 *
 * \see void ecrt_master_application_time()
 *
 * \param TV struct timeval containing epoch time.
 */
#define EC_TIMEVAL2NANO(TV) \
    (((TV).tv_sec - 946684800ULL) * 1000000000ULL + (TV).tv_usec * 1000ULL)

/** Size of a CoE emergency message in byte.
 *CoE紧急消息的大小(字节)。
 * \see ecrt_slave_config_emerg_pop().
 */
#define EC_COE_EMERGENCY_MSG_SIZE 8

/******************************************************************************
 *03 Data types数据类型
 *****************************************************************************/

struct ec_master;
typedef struct ec_master ec_master_t; /**< \see ec_master */

struct ec_slave_config;
typedef struct ec_slave_config ec_slave_config_t; /**< \see ec_slave_config */

struct ec_domain;
typedef struct ec_domain ec_domain_t; /**< \see ec_domain */

struct ec_sdo_request;
typedef struct ec_sdo_request ec_sdo_request_t; /**< \see ec_sdo_request. */

struct ec_voe_handler;
typedef struct ec_voe_handler ec_voe_handler_t; /**< \see ec_voe_handler. */

struct ec_reg_request;
typedef struct ec_reg_request ec_reg_request_t; /**< \see ec_sdo_request. */

/*****************************************************************************/

/**01 Master state.
 *主站状态
 * This is used for the output parameter of ecrt_master_state().
 *函数ecrt_master_state()的输出参数
 * \see ecrt_master_state().
 */
typedef struct {
    unsigned int slaves_responding; /**< Sum of responding slaves on all
                                      Ethernet devices.所有以太网设备上响应slave的总数。 */
    unsigned int al_states : 4; /**< Application-layer states of all slaves.所有从站应用层状态
                                  The states are coded in the lower 4 bits.被用低四位进行编码
                                  If a bit is set, it means that at least one如果一位被设置，意味着至少一个
                                  slave in the bus is in the corresponding从站在总线上有响应
                                  state:
                                  - Bit 0: \a INIT
                                  - Bit 1: \a PREOP
                                  - Bit 2: \a SAFEOP
                                  - Bit 3: \a OP */
    unsigned int link_up : 1; /**< \a true, if at least one Ethernet link is为真，至少有一个连接连上
                                up. */
} ec_master_state_t;

/*****************************************************************************/

/**02 Redundant link state.
 *冗余链路状态。
 * This is used for the output parameter of ecrt_master_link_state().
 *这用于ecrt主链接状态()的输出参数。
 * \see ecrt_master_link_state().
 */
typedef struct {
    unsigned int slaves_responding; /**< Sum of responding slaves on the given
                                      link. */
    unsigned int al_states : 4; /**< Application-layer states of the slaves on
                                  the given link.  The states are coded in the
                                  lower 4 bits.  If a bit is set, it means
                                  that at least one slave in the bus is in the
                                  corresponding state:
                                  - Bit 0: \a INIT
                                  - Bit 1: \a PREOP
                                  - Bit 2: \a SAFEOP
                                  - Bit 3: \a OP */
    unsigned int link_up : 1; /**< \a true, if the given Ethernet link is up.
                               */
} ec_master_link_state_t;

/*****************************************************************************/

/**03 Slave configuration state.
 *从站配置状态
 * This is used as an output parameter of ecrt_slave_config_state().
 用于函数ecrt_slave_config_state()输出参数
 * \see ecrt_slave_config_state().
 */
typedef struct  {
    unsigned int online : 1; /**< The slave is online. 从站在线*/
    unsigned int operational : 1; /**< The slave was brought into \a OP state从站被带入操作状态
                                    using the specified configuration. 使用指定配置*/
    unsigned int al_state : 4; /**< The application-layer state of the slave.从站应用层状态
                                 - 1: \a INIT
                                 - 2: \a PREOP
                                 - 4: \a SAFEOP
                                 - 8: \a OP

                                 Note that each state is coded in a different
                                 bit! 注意不同的状态使用不同的位*/
} ec_slave_config_state_t;

/*****************************************************************************/

/**04 Master information.
 *主站信息
 * This is used as an output parameter of ecrt_master().
 *用于函数ecrt_master()输出参数
 * \see ecrt_master().
 */
typedef struct {
   unsigned int slave_count; /**< Number of slaves in the bus. 总线上从站数*/
   unsigned int link_up : 1; /**< \a true, if the network link is up. 为真，一个网络连接上*/
   uint8_t scan_busy; /**< \a true, while the master is scanning the bus 为真，主站正在扫描总线*/
   uint64_t app_time; /**< Application time. 应用时间*/
} ec_master_info_t;

/*****************************************************************************/

/**05 EtherCAT slave port descriptor.
    EherCAT 从站端口描述
 */
typedef enum {
    EC_PORT_NOT_IMPLEMENTED, /**< Port is not implemented.端口没有实现 */
    EC_PORT_NOT_CONFIGURED, /**< Port is not configured. 端口没有配置*/
    EC_PORT_EBUS, /**< Port is an E-Bus.端口是E-Bus */
    EC_PORT_MII /**< Port is a MII.端口是 MII */
} ec_slave_port_desc_t;

/*****************************************************************************/

/**06 EtherCAT slave port information.
    从站端口信息
 */
typedef struct {
    uint8_t link_up; /**< Link detected.检测到连接 */
    uint8_t loop_closed; /**< Loop closed.循环关闭 */
    uint8_t signal_detected; /**< Detected signal on RX port.在RX端口检测到信号 */
} ec_slave_port_link_t;

/*****************************************************************************/

/**07 Slave information.
 *从站信息
 * This is used as an output parameter of ecrt_master_get_slave().
 *用于函数ecrt_master_get_slave()的输出参数
 * \see ecrt_master_get_slave().
 */
typedef struct {
    uint16_t position; /**< Offset of the slave in the ring.从站在位置环中的偏移 */
    uint32_t vendor_id; /**< Vendor-ID stored on the slave. 存储在从站中的供应商ID*/
    uint32_t product_code; /**< Product-Code stored on the slave.存储在从站中的产品代码 */
    uint32_t revision_number; /**< Revision-Number stored on the slave. */
    uint32_t serial_number; /**< Serial-Number stored on the slave. */
    uint16_t alias; /**< The slaves alias if not equal to 0.不等于0时候从站假名 */
    int16_t current_on_ebus; /**< Used current in mA. */
    struct {
        ec_slave_port_desc_t desc; /**< Physical port type. */
        ec_slave_port_link_t link; /**< Port link state. */
        uint32_t receive_time; /**< Receive time on DC transmission delay
                                 measurement. */
        uint16_t next_slave; /**< Ring position of next DC slave on that
                               port.  */
        uint32_t delay_to_next_dc; /**< Delay [ns] to next DC slave. */
    } ports[EC_MAX_PORTS]; /**< Port information. 端口信息*/
    uint8_t al_state; /**< Current state of the slave.从站当前状态 */
    uint8_t error_flag; /**< Error flag for that slave.从站错误标志 */
    uint8_t sync_count; /**< Number of sync managers.同步管理器数量 */
    uint16_t sdo_count; /**< Number of SDOs.SDO数量 */
    char name[EC_MAX_STRING_LENGTH]; /**< Name of the slave. 从站名字*/
} ec_slave_info_t;

/*****************************************************************************/

/**08 Domain working counter interpretation.
 *域工作计数解释
 * This is used in ec_domain_state_t.
 */
typedef enum {
    EC_WC_ZERO = 0,   /**< No registered process data were exchanged. 没有交换注册的过程数据。*/
    EC_WC_INCOMPLETE, /**< Some of the registered process data were一些注册的进程数据被交换
                        exchanged. */
    EC_WC_COMPLETE    /**< All registered process data were exchanged. 交换了所有注册的过程数据*/
} ec_wc_state_t;

/*****************************************************************************/

/**09 Domain state.
 *域状态
 * This is used for the output parameter of ecrt_domain_state().
 */
typedef struct {
    unsigned int working_counter; /**< Value of the last working counter. 最后一个工作计数器的值*/
    ec_wc_state_t wc_state; /**< Working counter interpretation. 工作计数器的状态*/
    unsigned int redundancy_active; /**< Redundant link is in use. 冗余链接正在使用中。*/
} ec_domain_state_t;

/*****************************************************************************/

/**10 Direction type for PDO assignment functions.PDO分配函数的方向类型。
 */
typedef enum {
    EC_DIR_INVALID, /**< Invalid direction. Do not use this value.无效的方向。不要使用这个值。”*/
    EC_DIR_OUTPUT, /**< Values written by the master. 主站写的值*/
    EC_DIR_INPUT, /**< Values read by the master. 主站读的值*/
    EC_DIR_COUNT /**< Number of directions. For internal use only. 数量的方向。只供内部使用*/
} ec_direction_t;

/*****************************************************************************/

/**11 Watchdog mode for sync manager configuration.
 *同步管理器配置看门狗模式
 * Used to specify, if a sync manager's watchdog is to be enabled.
 */
typedef enum {
    EC_WD_DEFAULT, /**< Use the default setting of the sync manager.使用默认同步管理器设置 */
    EC_WD_ENABLE, /**< Enable the watchdog.使能看门狗 */
    EC_WD_DISABLE, /**< Disable the watchdog. 不使能看门狗*/
} ec_watchdog_mode_t;

/*****************************************************************************/

/**12 PDO entry configuration information.
 *PDo表项配置信息。
 * This is the data type of the \a entries field in ec_pdo_info_t.
 *
 * \see ecrt_slave_config_pdos().
 */
typedef struct {
    uint16_t index; /**< PDO entry index. PDO条目索引*/
    uint8_t subindex; /**< PDO entry subindex. PDO条目子索引*/
    uint8_t bit_length; /**< Size of the PDO entry in bit. PDO条目按位计算的大小*/
} ec_pdo_entry_info_t;

/*****************************************************************************/

/**13 PDO configuration information.
 *PDo配置信息。
 * This is the data type of the \a pdos field in ec_sync_info_t.
 *
 * \see ecrt_slave_config_pdos().
 */
typedef struct {
    uint16_t index; /**< PDO index. */
    unsigned int n_entries; /**< Number of PDO entries in \a entries to map.
                              Zero means, that the default mapping shall be
                              used (this can only be done if the slave is
                              present at bus configuration time). */
    ec_pdo_entry_info_t *entries; /**< Array of PDO entries to map. Can either
                                    be \a NULL, or must contain at
                                    least \a n_entries values. */
} ec_pdo_info_t;

/*****************************************************************************/

/**14 Sync manager configuration information.
 *同步管理器配置信息
 * This can be use to configure multiple sync managers including the PDO
 * assignment and PDO mapping. It is used as an input parameter type in
 * ecrt_slave_config_pdos().
 这可以用来配置多个同步管理器，包括PDO分配和PDO mappinq。
 它被用作输入参数类型ecrt_salve_config pdos()。
 */
typedef struct {
    uint8_t index; /**< Sync manager index. Must be less同步管理器索引，必须小于
                     than #EC_MAX_SYNC_MANAGERS for a valid sync manager作为一个合法的同步管理器,
                     but can also be \a 0xff to mark the end of the list. 也可以用0xff作为结束的标志*/
    ec_direction_t dir; /**< Sync manager direction. 同步管理器的方向*/
    unsigned int n_pdos; /**< Number of PDOs in \a pdos. PDO的数量*/
    ec_pdo_info_t *pdos; /**< Array with PDOs to assign. This must contain被分配的PDO的数组，必须包含N条PDOS
                            at least \a n_pdos PDOs. */
    ec_watchdog_mode_t watchdog_mode; /**< Watchdog mode.看门狗模式 */
} ec_sync_info_t;

/*****************************************************************************/

/**15 List record type for PDO entry mass-registration.
 *列出PDO输入批量注册的记录类型。
 * This type is used for the array parameter of the
 * 该类型用于数组参数
 * ecrt_domain_reg_pdo_entry_list()
 */
typedef struct {
    uint16_t alias; /**< Slave alias address. 从站假名地址*/
    uint16_t position; /**< Slave position. 从站位置*/
    uint32_t vendor_id; /**< Slave vendor ID. 从站供应商ID*/
    uint32_t product_code; /**< Slave product code. 从站产品编码*/
    uint16_t index; /**< PDO entry index.PDO条目索引 */
    uint8_t subindex; /**< PDO entry subindex. PDO条目子索引*/
    unsigned int *offset; /**< Pointer to a variable to store the PDO entry's用于存储PDO表项的变量指针
                       (byte-)offset in the process data. 在过程数据中的偏移*/
    unsigned int *bit_position; /**< Pointer to a variable to store a bit
                                  position (0-7) within the \a offset. Can be
                                  NULL, in which case an error is raised if the
                                  PDO entry does not byte-align. /**<指向一个变量的指针，
								  用于在\a偏移量中存储位(0-7)。可以为NULL，在这种情况下，
								  如果PDO条目没有按字节对齐，将引发错误。*／u*/
} ec_pdo_entry_reg_t;

/*****************************************************************************/

/**16 Request state.
 *请求状态
 * This is used as return type for ecrt_sdo_request_state() and
 * ecrt_voe_handler_state().
 */
typedef enum {
    EC_REQUEST_UNUSED, /**< Not requested. 没有请求*/
    EC_REQUEST_BUSY, /**< Request is being processed. 请求正在处理*/
    EC_REQUEST_SUCCESS, /**< Request was processed successfully. 请求处理成功*/
    EC_REQUEST_ERROR, /**< Request processing failed. 请求处理失败*/
} ec_request_state_t;

/*****************************************************************************/

/**17 Application-layer state.应用层状态
 */
typedef enum {
    EC_AL_STATE_INIT = 1, /**< Init. 初始化*/
    EC_AL_STATE_PREOP = 2, /**< Pre-operational.预操作 */
    EC_AL_STATE_SAFEOP = 4, /**< Safe-operational. 安全操作*/
    EC_AL_STATE_OP = 8, /**< Operational. 操作*/
} ec_al_state_t;

/******************************************************************************
 *04 Global functions  全局函数
 *****************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

/**01 Returns the version magic of the realtime interface.
 *返回实时接口的版本魔法。
 * \return Value of ECRT_VERSION_MAGIC() at EtherCAT master compile time.
 */
unsigned int ecrt_version_magic(void);

/**02 Requests an EtherCAT master for realtime operation.
 *请求EtherCAT主机进行实时操作。
 * Before an application can access an EtherCAT master, it has to reserve one
 * for exclusive use.
 *在应用程序访问EtherCAT主机之前，它必须为独占使用预留一台主机。
 * In userspace, this is a convenience function for ecrt_open_master() and
 * ecrt_master_reserve().
 *在用户空间中，这是一个方便的函数，用于ecrt open master()和ecrt master reserve()。我
 * This function has to be the first function an application has to call to
 * use EtherCAT. The function takes the index of the master as its argument.
 * The first master has index 0, the n-th master has index n - 1. The number
 * of masters has to be specified when loading the master module.
 *这个函数必须是应用程序使用EtherCAT必须调用的第一个函数。该函数以master的索引作为参数。
 *第一个主节点索引为0，第n个主节点索引为n- 1。加载主模块时必须指定主模块的数量。
 * \return Pointer to the reserved master, otherwise \a NULL.
 */
ec_master_t *ecrt_request_master(
        unsigned int master_index /**< Index of the master to request.主站请求索引 */
        );

#ifndef __KERNEL__

/**03 Opens an EtherCAT master for userspace access.
 *
 * This function has to be the first function an application has to call to
 * use EtherCAT. The function takes the index of the master as its argument.
 * The first master has index 0, the n-th master has index n - 1. The number
 * of masters has to be specified when loading the master module.
 *这个函数必须是应用程序使用EtherCAT必须调用的第一个函数。该函数以master的索引作为参数。
 *第一个主节点索引为0，第n个主节点索引为n -1。加载主模块时必须指定主模块的数量。
 * For convenience, the function ecrt_request_master() can be used.
 *为了方便．
 * \return Pointer to the opened master, otherwise \a NULL.
 */
ec_master_t *ecrt_open_master(
        unsigned int master_index /**< Index of the master to request. 主站请求索引。*/
        );

#endif // #ifndef __KERNEL__

/**04 Releases a requested EtherCAT master.
 *•释放请求的EtherCAT主站
 * After use, a master it has to be released to make it available for other
 * applications.
 *在使用后，master必须被释放，以使其他应用程序可以使用它。
 * This method frees all created data structures. It should not be called in
 * realtime context.
 *此方法释放所有创建的数据结构。不应该在实时上下文中调用它。
 * If the master was activated, ecrt_master_deactivate() is called internally.
 */
void ecrt_release_master(
        ec_master_t *master /**< EtherCAT master主站 */
        );

/******************************************************************************
 *05 Master methods 主站方法
 *****************************************************************************/

#ifndef __KERNEL__

/**01 Reserves an EtherCAT master for realtime operation.
 *为实时操作保留一个EtherCAT主机。
 * Before an application can use PDO/domain registration functions or SDO
 * request functions on the master, it has to reserve one for exclusive use.
 *在应用程序可以在主服务器上使用PDo/域注册函数或sDo请求函数之前，它必须保留一个单独使用。
 * \return 0 in case of success, else < 0
 */
int ecrt_master_reserve(
        ec_master_t *master /**< EtherCAT master 主站*/
        );

#endif // #ifndef __KERNEL__

#ifdef __KERNEL__

/**02 Sets the locking callbacks.
 *设置锁定回调。
 * For concurrent master access, i. e. if other instances than the application
 * want to send and receive datagrams on the bus, the application has to
 * provide a callback mechanism. This method takes two function pointers as
 * its parameters. Asynchronous master access (like EoE processing) is only
 * possible if the callbacks have been set.
 *对于并发主访问，也就是说，如果应用程序以外的其他实例想要在总线上发送和接收数据报，
 *应用程序必须提供一个回调机制。该方法以两个函数指针作为参数。异步主访问(如EoE处理)
 *只有在设置了回调之后才可能实现。
 * The task of the send callback (\a send_cb) is to decide, if the bus is
 * currently accessible and whether or not to call the ecrt_master_send_ext()
 * method.
 *发送回调(\a send cb)的任务是决定总线当前是否可访问，以及是否调用ecrt主send ext()方法。
 * The task of the receive callback (\a receive_cb) is to decide, if a call to
 * ecrt_master_receive() is allowed and to execute it respectively.
 *接收回调(\a receive cb)的任务是决定是否允许调用ecrt master receive()并分别执行它。
 * \attention This method has to be called before ecrt_master_activate().
 */
void ecrt_master_callbacks(
        ec_master_t *master, /**< EtherCAT master 主站*/
        void (*send_cb)(void *), /**< Datagram sending callback. 数据发送回调*/
        void (*receive_cb)(void *), /**< Receive callback. 接受回调*/
        void *cb_data /**< Arbitrary pointer passed to the callback functions.传递给回调函数的任意指针
                       */
        );

#endif /* __KERNEL__ */

/**03 Creates a new process data domain.
 *创建一个新的流程数据域。
 * For process data exchange, at least one process data domain is needed.
 * This method creates a new process data domain and returns a pointer to the
 * new domain object. This object can be used for registering PDOs and
 * exchanging them in cyclic operation.
 *对于进程数据交换，至少需要一个进程数据域。此方法创建一个新的进程数据域，
 *并返回一个指向新域对象的指针。该节点可用于注册和循环操作的pdo交换。
 * This method allocates memory and should be called in non-realtime context
 * before ecrt_master_activate().
 *这个方法分配内存，并且应该在非实时环境中'在ecrt master activate()之前'被调用。
 * \return Pointer to the new domain on success, else NULL.
 */
ec_domain_t *ecrt_master_create_domain(
        ec_master_t *master /**< EtherCAT master. */
        );

/**04 Obtains a slave configuration.
 *获取slave配置。
 * Creates a slave configuration object for the given \a alias and \a position
 * tuple and returns it. If a configuration with the same \a alias and \a
 * position already exists, it will be re-used. In the latter case, the given
 * vendor ID and product code are compared to the stored ones. On mismatch, an
 * error message is raised and the function returns \a NULL.
 *为给定的一个别名和一个位置元组创建一个从属配置对象并返回它。如果具有相同的别名和位置
 *的配置已经存在，它将被重用。在后一种情况下，将给定的供应商ID和产品代码与存储的ID和产品
 *代码进行比较。如果不匹配，则抛出一个错误消息并返回一个NULL。
 * Slaves are addressed with the \a alias and \a position parameters.
 * - If \a alias is zero, \a position is interpreted as the desired slave's
 *   ring position.
 * - If \a alias is non-zero, it matches a slave with the given alias. In this
 *   case, \a position is interpreted as ring offset, starting from the
 *   aliased slave, so a position of zero means the aliased slave itself and a
 *   positive value matches the n-th slave behind the aliased one.
 *从机是用一个别名和一个位置参数寻址的。—如果一个别名为零，一个位置将被解释为
 所需的从属环位置。如果一个别名是非零的，它将用给定的别名匹配一个slave。在这种
 情况下，\a的位置被解释为环形偏移，从别名从属器开始，所以零的位置意味着别名从属
 器本身，一个正值匹配别名从属器后面的第n个从属器。
 * If the slave with the given address is found during the bus configuration,
 * its vendor ID and product code are matched against the given value. On
 * mismatch, the slave is not configured and an error message is raised.
 *如果在总线配置期间找到具有给定地址的从服务器，则它的供应商ID和产品代码
 与给定值匹配。如果不匹配，则不配置从服务器并引发错误消息。
 * If different slave configurations are pointing to the same slave during bus
 * configuration, a warning is raised and only the first configuration is
 * applied.
 *如果在总线. configuration期间不同的从服务器配置指向相同的从服务器，则会引发一个警告，并且只应用第一个配置。
 * This method allocates memory and should be called in non-realtime context
 * before ecrt_master_activate().
 *这个方法分配内存，并且应该在非实时环境中在ecrt master activate()之前被调用。
 * \retval >0 Pointer to the slave configuration structure.
 * \retval NULL in the error case.
 */
ec_slave_config_t *ecrt_master_slave_config(
        ec_master_t *master, /**< EtherCAT master 主站*/
        uint16_t alias, /**< Slave alias. 从站假名*/
        uint16_t position, /**< Slave position.从站位置 */
        uint32_t vendor_id, /**< Expected vendor ID.期望的供应商ID */
        uint32_t product_code /**< Expected product code. 期望的产品代码*/
        );

/**05 Selects the reference clock for distributed clocks.
 *为分布式时钟选择参考时钟。
 * If this method is not called for a certain master, or if the slave
 * configuration pointer is NULL, then the first slave with DC functionality
 * will provide the reference clock.
 *如果某个主服务器没有调用此方法，或者从服务器的. configuration指针为NULL，
 那么第一个具有DC功能的从服务器将提供参考时钟。
 * \return 0 on success, otherwise negative error code.
 */
int ecrt_master_select_reference_clock(
        ec_master_t *master, /**< EtherCAT master. 主站*/
        ec_slave_config_t *sc /**< Slave config of the slave to use as the
                               * reference slave (or NULL).作为参考从站的从站配置（或为空） */
        );

/**06 Obtains master information.
 *得到主站的信息。
 * No memory is allocated on the heap in
 * this function.
 *在这个函数中，没有在堆上分配内存。
 * \attention The pointer to this structure must point to a valid variable.
 *
 * \return 0 in case of success, else < 0
 */
int ecrt_master(
        ec_master_t *master, /**< EtherCAT master 主站*/
        ec_master_info_t *master_info /**< Structure that will output the
                                        information 输出信息的结构体*/
        );

/**07 Obtains slave information.
 *获得从站信息。
 * Tries to find the slave with the given ring position. The obtained
 * information is stored in a structure. No memory is allocated on the heap in
 * this function.
 *尝试在给定的环位置找到从站。获得的信息存储在一个结构中。在这个函数中，没有在堆上分配内存。
 * \attention The pointer to this structure must point to a valid variable.
 *指向这个结构的指针必须指向一个有效的变量。
 * \return 0 in case of success, else < 0
 */
int ecrt_master_get_slave(
        ec_master_t *master, /**< EtherCAT master 主站*/
        uint16_t slave_position, /**< Slave position.从站位置 */
        ec_slave_info_t *slave_info /**< Structure that will output the
                                      information输出信息的结构 */
        );

#ifndef __KERNEL__

/**08 Returns the proposed configuration of a slave's sync manager.
 *返回slave的同步管理器的建议配置。
 * Fills a given ec_sync_info_t structure with the attributes of a sync
 * manager. The \a pdos field of the return value is left empty. Use
 * ecrt_master_get_pdo() to get the PDO information.
 *用同步管理器的属性填充给定的ec同步信息结构。返回值的pdos字段为空。
 使用ecrt master get pdo()来获取pdo信息。
 * \return zero on success, else non-zero
 */
int ecrt_master_get_sync_manager(
        ec_master_t *master, /**< EtherCAT master. 主站*/
        uint16_t slave_position, /**< Slave position. 从站位置*/
        uint8_t sync_index, /**< Sync manager index. Must be less
                                than #EC_MAX_SYNC_MANAGERS.同步管理器指数。
								必须小于#EC MAX SYNC MANAGERS。＊ */
        ec_sync_info_t *sync /**< Pointer to output structure. 输出结构体指针*/
        );

/**09 Returns information about a currently assigned PDO.
 *返回当前分配的PDO的信息。
 * Fills a given ec_pdo_info_t structure with the attributes of a currently
 * assigned PDO of the given sync manager. The \a entries field of the return
 * value is left empty. Use ecrt_master_get_pdo_entry() to get the PDO
 * entry information.
 *
 * \retval zero on success, else non-zero
 */
int ecrt_master_get_pdo(
        ec_master_t *master, /**< EtherCAT master. 主站*/
        uint16_t slave_position, /**< Slave position. 从站位置*/
        uint8_t sync_index, /**< Sync manager index. Must be less
                                 than #EC_MAX_SYNC_MANAGERS. 同步管理器索引，必须小于*/
        uint16_t pos, /**< Zero-based PDO position.PDO 0位置 */
        ec_pdo_info_t *pdo /**< Pointer to output structure. 指向输出指针*/
        );

/**10 Returns information about a currently mapped PDO entry.
 *返回关于当前映射的PDO条目的信息。
 * Fills a given ec_pdo_entry_info_t structure with the attributes of a
 * currently mapped PDO entry of the given PDO.
 *
 * \retval zero on success, else non-zero 0则成功，其他非0
 */
int ecrt_master_get_pdo_entry(
        ec_master_t *master, /**< EtherCAT master. 主站*/
        uint16_t slave_position, /**< Slave position. 从站位置*/
        uint8_t sync_index, /**< Sync manager index. Must be less
                                 than #EC_MAX_SYNC_MANAGERS. 同步管理器索引，必须小于*/
        uint16_t pdo_pos, /**< Zero-based PDO position. PDO O位置*/
        uint16_t entry_pos, /**< Zero-based PDO entry position. PDO条目 0位置*/
        ec_pdo_entry_info_t *entry /**< Pointer to output structure.指向输出指针 */
        );

#endif /* #ifndef __KERNEL__ */

/**11 Executes an SDO download request to write data to a slave.
 *
 * This request is processed by the master state machine. This method blocks,
 * until the request has been processed and may not be called in realtime
 * context.
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_master_sdo_download(
        ec_master_t *master, /**< EtherCAT master. */
        uint16_t slave_position, /**< Slave position. */
        uint16_t index, /**< Index of the SDO. */
        uint8_t subindex, /**< Subindex of the SDO. */
        uint8_t *data, /**< Data buffer to download. */
        size_t data_size, /**< Size of the data buffer. */
        uint32_t *abort_code /**< Abort code of the SDO download. */
        );

/**12 Executes an SDO download request to write data to a slave via complete
 * access.
 *
 * This request is processed by the master state machine. This method blocks,
 * until the request has been processed and may not be called in realtime
 * context.
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_master_sdo_download_complete(
        ec_master_t *master, /**< EtherCAT master. */
        uint16_t slave_position, /**< Slave position. */
        uint16_t index, /**< Index of the SDO. */
        uint8_t *data, /**< Data buffer to download. */
        size_t data_size, /**< Size of the data buffer. */
        uint32_t *abort_code /**< Abort code of the SDO download. */
        );

/**13 Executes an SDO upload request to read data from a slave.
 *
 * This request is processed by the master state machine. This method blocks,
 * until the request has been processed and may not be called in realtime
 * context.
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_master_sdo_upload(
        ec_master_t *master, /**< EtherCAT master. */
        uint16_t slave_position, /**< Slave position. */
        uint16_t index, /**< Index of the SDO. */
        uint8_t subindex, /**< Subindex of the SDO. */
        uint8_t *target, /**< Target buffer for the upload. */
        size_t target_size, /**< Size of the target buffer. */
        size_t *result_size, /**< Uploaded data size. */
        uint32_t *abort_code /**< Abort code of the SDO upload. */
        );

/**14 Executes an SoE write request.
 *
 * Starts writing an IDN and blocks until the request was processed, or an
 * error occurred.
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_master_write_idn(
        ec_master_t *master, /**< EtherCAT master. */
        uint16_t slave_position, /**< Slave position. */
        uint8_t drive_no, /**< Drive number. */
        uint16_t idn, /**< SoE IDN (see ecrt_slave_config_idn()). */
        uint8_t *data, /**< Pointer to data to write. */
        size_t data_size, /**< Size of data to write. */
        uint16_t *error_code /**< Pointer to variable, where an SoE error code
                               can be stored. */
        );

/**15 Executes an SoE read request.
 *
 * Starts reading an IDN and blocks until the request was processed, or an
 * error occurred.
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_master_read_idn(
        ec_master_t *master, /**< EtherCAT master. */
        uint16_t slave_position, /**< Slave position. */
        uint8_t drive_no, /**< Drive number. */
        uint16_t idn, /**< SoE IDN (see ecrt_slave_config_idn()). */
        uint8_t *target, /**< Pointer to memory where the read data can be
                           stored. */
        size_t target_size, /**< Size of the memory \a target points to. */
        size_t *result_size, /**< Actual size of the received data. */
        uint16_t *error_code /**< Pointer to variable, where an SoE error code
                               can be stored. */
        );

/**16 Finishes the configuration phase and prepares for cyclic operation.
 *完成配置阶段并准备循环操作。
 * This function tells the master that the configuration phase is finished and
 * the realtime operation will begin. The function allocates internal memory
 * for the domains and calculates the logical FMMU addresses for domain
 * members. It tells the master state machine that the bus configuration is
 * now to be applied.
 *这个函数告诉主机配置阶段已经完成，实时操作将开始。该函数为域分配内部内存，
 并计算域成员的逻辑FMMU地址。它告诉主站状态机现在要应用总线配置。
 * \attention After this function has been called, the realtime application is
 * in charge of cyclically calling ecrt_master_send() and
 * ecrt_master_receive() to ensure bus communication. Before calling this
 * function, the master thread is responsible for that, so these functions may
 * not be called! The method itself allocates memory and should not be called
 * in realtime context.
 *这个函数被调用后，实时应用程序负责循环调用ecrt master send()和Ecrt master receive()
 *确保总线通信。在调用这个函数之前，主站线程负责这个，所以这些函数可能不会被调用!方法本身
 *分配内存，不应该在实时上下文中调用。
 * \return 0 in case of success, else < 0
 */
int ecrt_master_activate(
        ec_master_t *master /**< EtherCAT master. */
        );

/**17 Deactivates the master.
 *
 * Removes the bus configuration. All objects created by
 * ecrt_master_create_domain(), ecrt_master_slave_config(), ecrt_domain_data()
 * ecrt_slave_config_create_sdo_request() and
 * ecrt_slave_config_create_voe_handler() are freed, so pointers to them
 * become invalid.
 *
 * This method should not be called in realtime context.
 */
void ecrt_master_deactivate(
        ec_master_t *master /**< EtherCAT master. */
        );

/**18 Set interval between calls to ecrt_master_send().
 *设置时间间隔在调用ecrt_master_send().
 * This information helps the master to decide, how much data can be appended
 * to a frame by the master state machine. When the master is configured with
 * --enable-hrtimers, this is used to calculate the scheduling of the master
 * thread.
 *这些信息帮助主站状态机决定，主站状态机可以向帧中追加多少数据。当主站线程配置
 为——enable-hrtimers时，它用于计算主线程的调度。
 * \retval 0 on success.
 * \retval <0 Error code.
 */
int ecrt_master_set_send_interval(
        ec_master_t *master, /**< EtherCAT master. */
        size_t send_interval /**< Send interval间隔 in us */
        );

/**19 Sends all datagrams in the queue.
 *发送队列中的所有数据报。
 * This method takes all datagrams, that have been queued for transmission,
 * puts them into frames, and passes them to the Ethernet device for sending.
 *该方法将已排队等待传输的所有数据报放入帧中，并将其传递给以太网设备进行发送。
 * Has to be called cyclically by the application after ecrt_master_activate()
 * has returned.
 *必须在ecrt master activate()返回后由应用程序循环调用。
 */
void ecrt_master_send(
        ec_master_t *master /**< EtherCAT master. */
        );

/**20 Fetches received frames from the hardware and processes the datagrams.
 *从硬件中获取接收的帧并处理数据报。
 * Queries the network device for received frames by calling the interrupt
 * service routine. Extracts received datagrams and dispatches the results to
 * the datagram objects in the queue. Received datagrams, and the ones that
 * timed out, will be marked, and dequeued.
 *通过调用中断服务程序来查询网络设备接收到的帧。提取接收到的数据报，并将结果
 *分派给队列中的数据报对象。接收到的数据报和超时的数据报将被标记并退出队列。
 * Has to be called cyclically by the realtime application after
 * ecrt_master_activate() has returned.
 */
void ecrt_master_receive(
        ec_master_t *master /**< EtherCAT master. */
        );

/**21 Sends non-application datagrams.
 *发送非应用数据
 * This method has to be called in the send callback function passed via
 * ecrt_master_callbacks() to allow the sending of non-application datagrams.
 */
void ecrt_master_send_ext(
        ec_master_t *master /**< EtherCAT master. */
        );

/**22 Reads the current master state.
 *
 * Stores the master state information in the given \a state structure.
 *
 * This method returns a global state. For the link-specific states in a
 * redundant bus topology, use the ecrt_master_link_state() method.
 */
void ecrt_master_state(
        const ec_master_t *master, /**< EtherCAT master. */
        ec_master_state_t *state /**< Structure to store the information. */
        );

/**23 Reads the current state of a redundant link.
 *
 * Stores the link state information in the given \a state structure.
 *
 * \return Zero on success, otherwise negative error code.
 */
int ecrt_master_link_state(
        const ec_master_t *master, /**< EtherCAT master. */
        unsigned int dev_idx, /**< Index of the device (0 = main device, 1 =
                                first backup device, ...). */
        ec_master_link_state_t *state /**< Structure to store the information.
                                       */
        );

/**24 Sets the application time.
 *设置应用程序时间。
 * The master has to know the application's time when operating slaves with
 * distributed clocks. The time is not incremented by the master itself, so
 * this method has to be called cyclically.
 *当使用分布式时钟操作从站时，主站必须知道应用程序的时间。时间不是
 *由主机本身增加的，所以这个方法必须循环调用。
 * \attention The time passed to this method is used to calculate the phase of
 * the slaves' SYNC0/1 interrupts. It should be called constantly at the same
 * point of the realtime cycle. So it is recommended to call it at the start
 * of the calculations to avoid deviancies due to changing execution times.
 *注意：传递到该方法的时间用于计算从站的SYNC0/1中断的阶段。它应该在实时周期的同一“点”
 不断地被调用。因此建议在计算开始时调用它，以避免由于更改执行时间而导致的偏差。
 * The time is used when setting the slaves' <tt>System Time Offset</tt> and
 * <tt>Cyclic Operation Start Time</tt> registers and when synchronizing the
 * DC reference clock to the application time via
 * ecrt_master_sync_reference_clock().
 *当设置从机的<tt>系统时间偏移</tt>和循环操作开始时间</tt>寄存器和
 当DC参考时钟通过应用程序时间同步时使用主站同步参考时钟()。
 * The time is defined as nanoseconds from 2000-01-01 00:00. Converting an
 * epoch time can be done with the EC_TIMEVAL2NANO() macro, but is not
 * necessary, since the absolute value is not of any interest.
 时间定义为从2000-01-01 00:00开始的纳秒。转换一个•epoch时间可以用
 EC TIMEVAL2NANO()宏完成，但这不是必需的，因为绝对值没有任何意义。
 */
void ecrt_master_application_time(
        ec_master_t *master, /**< EtherCAT master. */
        uint64_t app_time /**< Application time. */
        );

/**25 Queues the DC reference clock drift compensation datagram for sending.
 *． 将DC参考时钟漂移补偿数据报排队以便发送。
 * The reference clock will by synchronized to the application time provided
 * by the last call off ecrt_master_application_time().
 参考时钟将与最后调用ecrt主应用程序时间()提供的应用程序时间同步。
 */
void ecrt_master_sync_reference_clock(
        ec_master_t *master /**< EtherCAT master. */
        );

/**26 Queues the DC reference clock drift compensation datagram for sending.
 *将用于发送的DC基准时钟漂移补偿数据报排队。
 * The reference clock will by synchronized to the time passed in the
 * sync_time parameter.
 * 参考时钟在同步时间参数同步到过去的时间
 */
void ecrt_master_sync_reference_clock_to(
        ec_master_t *master, /**< EtherCAT master. 主站*/
        uint64_t sync_time /**< Sync reference clock to this time.同步参考时钟到这个世界 */
        );

/**27 Queues the DC clock drift compensation datagram for sending.
 *将用于发送的DC时钟漂移补偿数据报排队。
 * All slave clocks synchronized to the reference clock.
 * 所有从站时钟同步到参考时钟
 */
void ecrt_master_sync_slave_clocks(
        ec_master_t *master /**< EtherCAT master. */
        );

/**28 Get the lower 32 bit of the reference clock system time.
 *得到低32位的参考时钟系统时间
 * This method can be used to synchronize the master to the reference clock.
 *这个方法用于同步主站到参考时钟
 * The reference clock system time is queried via the参考时钟的系统时间通过这个函数方法确认
 * ecrt_master_sync_slave_clocks() method, that reads the system time of the
 * reference clock and writes it to the slave clocks (so be sure to call it
 * cyclically to get valid data).
 * （请确认周期性调用这个函数用来获得合法数据）
 *
 * \attention The returned time is the system time of the reference clock
 * minus the transmission delay of the reference clock.
 *注意：返回时间是参考时钟的系统时间减去参考时钟的传输延迟
 * \retval 0 success, system time was written into \a time.
 * \retval -ENXIO No reference clock found.没有参考时钟
 * \retval -EIO Slave synchronization datagram was not received.伺服同步数据没有被接受
 */
int ecrt_master_reference_clock_time(
        ec_master_t *master, /**< EtherCAT master. */
        uint32_t *time /**< Pointer to store the queried system time. */
        );

/**29 Queues the DC synchrony monitoring datagram for sending.
 *将发送的DC同步监视数据报放入队列。
 * The datagram broadcast-reads all "System time difference" registers (\a
 * 0x092c) to get an upper estimation of the DC synchrony. The result can be
 * checked with the ecrt_master_sync_monitor_process() method.
 */
void ecrt_master_sync_monitor_queue(
        ec_master_t *master /**< EtherCAT master. */
        );

/**30 Processes the DC synchrony monitoring datagram.
 *处理DC同步监控数据。
 * If the sync monitoring datagram was sent before with
 * ecrt_master_sync_monitor_queue(), the result can be queried with this
 * method.
 *—如果同步监控数据报之前用Ecrt主同步监控队列()，结果可以用这个1方法查询。
 * \return Upper estimation of the maximum time difference in ns.
 */
uint32_t ecrt_master_sync_monitor_process(
        ec_master_t *master /**< EtherCAT master. */
        );

/**31 Retry configuring slaves.
 *重试配置从站
 * Via this method, the application can tell the master to bring all slaves to
 * OP state. In general, this is not necessary, because it is automatically
 * done by the master. But with special slaves, that can be reconfigured by
 * the vendor during runtime, it can be useful.
 *通过这个方法，应用程序可以告诉主站将所有从站设置为OP状态。一般来说，
 *这是不必要的，因为它是由主站自动完成的。但是对于特殊的从站(可以由供应商
 *在运行时重新配置)，它可能很有用。
 */
void ecrt_master_reset(
        ec_master_t *master /**< EtherCAT master. */
        );

/******************************************************************************
 *06 Slave configuration methods 从站配置方法
 *****************************************************************************/

/**01 Configure a sync manager.
 *配置同步管理器
 * Sets the direction of a sync manager. This overrides the direction bits
 * from the default control register from SII.
 * 设置同步管理器的方向。这将覆盖来自sIl的默认控制寄存器的方向位。
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *这个方法必须在非实时环境中在ecrt master activate()之前被调用。，
 * \return zero on success, else non-zero
 */
int ecrt_slave_config_sync_manager(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint8_t sync_index, /**< Sync manager index. Must be less
                              than #EC_MAX_SYNC_MANAGERS. */
        ec_direction_t direction, /**< Input/Output. */
        ec_watchdog_mode_t watchdog_mode /** Watchdog mode. */
        );

/**02 Configure a slave's watchdog times.
 *配置一个从站看门狗时间
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 */
void ecrt_slave_config_watchdog(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint16_t watchdog_divider, /**< Number of 40 ns intervals. Used as a
                                     base unit for all slave watchdogs. If set
                                     to zero, the value is not written, so the
                                     default is used. */
        uint16_t watchdog_intervals /**< Number of base intervals for process
                                      data watchdog. If set to zero, the value
                                      is not written, so the default is used.
                                     */
        );

/**03 Add a PDO to a sync manager's PDO assignment.
 *添加一个PDO到同步管理器的PDO分配中。
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \see ecrt_slave_config_pdos()
 * \return zero on success, else non-zero
 */
int ecrt_slave_config_pdo_assign_add(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint8_t sync_index, /**< Sync manager index. Must be less
                              than #EC_MAX_SYNC_MANAGERS. */
        uint16_t index /**< Index of the PDO to assign. */
        );

/**04 Clear a sync manager's PDO assignment.
 *清除同步管理器的PDO分配。
 * This can be called before assigning PDOs via
 * ecrt_slave_config_pdo_assign_add(), to clear the default assignment of a
 * sync manager.
 *
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \see ecrt_slave_config_pdos()
 */
void ecrt_slave_config_pdo_assign_clear(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint8_t sync_index /**< Sync manager index. Must be less
                              than #EC_MAX_SYNC_MANAGERS. */
        );

/**05 Add a PDO entry to the given PDO's mapping.
 *添加一个PDO条目到给定的PDO映射。
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \see ecrt_slave_config_pdos()
 * \return zero on success, else non-zero
 */
int ecrt_slave_config_pdo_mapping_add(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint16_t pdo_index, /**< Index of the PDO.PDO的索引 */
        uint16_t entry_index, /**< Index of the PDO entry to add to the PDO's
                                mapping. */
        uint8_t entry_subindex, /**< Subindex of the PDO entry to add to the
                                  PDO's mapping. */
        uint8_t entry_bit_length /**< Size of the PDO entry in bit. */
        );

/**06 Clear the mapping of a given PDO.
 *清除给定PDo的映射。
 * This can be called before mapping PDO entries via
 * ecrt_slave_config_pdo_mapping_add(), to clear the default mapping.
 *
 * This method has to be called in non-realtime context before
 该方法应该在非实时上下文中调用在主站激活函数之前。
 * ecrt_master_activate().
 *
 * \see ecrt_slave_config_pdos()
 */
void ecrt_slave_config_pdo_mapping_clear(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint16_t pdo_index /**< Index of the PDO. */
        );

/**07 Specify a complete PDO configuration.
 *指定一个完整的PDO配置。
 * This function is a convenience wrapper for the functions
 这个函数是函数的方便包装器
 * ecrt_slave_config_sync_manager(), ecrt_slave_config_pdo_assign_clear(),
 * ecrt_slave_config_pdo_assign_add(), ecrt_slave_config_pdo_mapping_clear()
 * and ecrt_slave_config_pdo_mapping_add(), that are better suitable for
 * automatic code generation.更适合自动代码生成。
 *
 * The following example shows, how to specify a complete configuration,
 * including the PDO mappings. With this information, the master is able to
 * reserve the complete process data, even if the slave is not present at
 * configuration time:
 *下面的示例展示了如何指定一个完整的配置，包括PDO映射。有了这些信息，
 *即使配置时从机不存在，主机也可以保留整个过程的数据:
 * \code
 * ec_pdo_entry_info_t el3162_channel1[] = {
 *     {0x3101, 1,  8}, // status
 *     {0x3101, 2, 16}  // value
 * };
 *
 * ec_pdo_entry_info_t el3162_channel2[] = {
 *     {0x3102, 1,  8}, // status
 *     {0x3102, 2, 16}  // value
 * };
 *
 * ec_pdo_info_t el3162_pdos[] = {
 *     {0x1A00, 2, el3162_channel1},
 *     {0x1A01, 2, el3162_channel2}
 * };
 *
 * ec_sync_info_t el3162_syncs[] = {
 *     {2, EC_DIR_OUTPUT},
 *     {3, EC_DIR_INPUT, 2, el3162_pdos},
 *     {0xff}
 * };
 *
 * if (ecrt_slave_config_pdos(sc_ana_in, EC_END, el3162_syncs)) {
 *     // handle error
 * }
 * \endcode
 *
 * The next example shows, how to configure the PDO assignment only. The
 * entries for each assigned PDO are taken from the PDO's default mapping.
 * Please note, that PDO entry registration will fail, if the PDO
 * configuration is left empty and the slave is offline.
 *下一个示例显示如何只配置PDo分配。每个分配的PDo的条目都来自PDo的默认映射。
 *请注意，如果PDO配置为空且从机离线，PDO条目注册将失败。
 * \code
 * ec_pdo_info_t pdos[] = {
 *     {0x1600}, // Channel 1
 *     {0x1601}  // Channel 2
 * };
 *
 * ec_sync_info_t syncs[] = {
 *     {3, EC_DIR_INPUT, 2, pdos},
 * };
 *
 * if (ecrt_slave_config_pdos(slave_config_ana_in, 1, syncs)) {
 *     // handle error
 * }
 * \endcode
 *
 * Processing of \a syncs will stop, if
 * - the number of processed items reaches \a n_syncs, or
 * - the \a index member of an ec_sync_info_t item is 0xff. In this case,
 *   \a n_syncs should set to a number greater than the number of list items;
 *   using EC_END is recommended.
 *处理\a同步将停止，如果-已处理项的数量达到n个同步，或一个ec同步信息项的索引
 *成员是Oxff。在这种情况下,n个同步应该设置为一个大于列表项数量的数字;推荐使用EC END。
 * This method has to be called in non-realtime context before
 *之前必须在非实时上下文中调用此方法
 * ecrt_master_activate().
 *
 * \return zero on success, else non-zero 0成功，其他非0
 */
int ecrt_slave_config_pdos(
        ec_slave_config_t *sc, /**< Slave configuration.从站配置 */
        unsigned int n_syncs, /**< Number of sync manager configurations in
                                \a syncs.同步管理配置数 */
        const ec_sync_info_t syncs[] /**< Array of sync manager
                                       configurations. 同步管理器配置数组*/
        );

/**08 Registers a PDO entry for process data exchange in a domain.
 *"为域中的进程数据交换注册一个PDo条目。
 * Searches the assigned PDOs for the given PDO entry. An error is raised, if
 * the given entry is not mapped. Otherwise, the corresponding sync manager
 * and FMMU configurations are provided for slave configuration and the
 * respective sync manager's assigned PDOs are appended to the given domain,
 * if not already done. The offset of the requested PDO entry's data inside
 * the domain's process data is returned. Optionally, the PDO entry bit
 * position (0-7) can be retrieved via the \a bit_position output parameter.
 * This pointer may be \a NULL, in this case an error is raised if the PDO
 * entry does not byte-align.
 *在指定的PDo中搜索给定的PDo条目。如果给定的条目没有被映射，则会引发错误。
 否则，相应的同步管理器和FMMU配置被提供给从配置和各自的同步管理器分配的pdo被
 追加到给定的域，如果没有完成的话。被请求的PDo条目的数据在域的进程数据中的偏
 移量被返回。可选的，PDO入口位位置(0-7)可以通过\位位置输出参数获得。这个指针
 可能是\a NULL，在这种情况下，如果PDO表项不进行字节对齐，则会引发错误。
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \retval >=0 Success: Offset of the PDO entry's process data.
 * \retval  <0 Error code.
 */
int ecrt_slave_config_reg_pdo_entry(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint16_t entry_index, /**< Index of the PDO entry to register. */
        uint8_t entry_subindex, /**< Subindex of the PDO entry to register. */
        ec_domain_t *domain, /**< Domain. */
        unsigned int *bit_position /**< Optional address if bit addressing
                                 is desired *如果需要位寻址，可选地址*/
        );

/**09 Registers a PDO entry using its position.
 *使用其位置重新注册PDO条目。
 * Similar to ecrt_slave_config_reg_pdo_entry(), but not using PDO indices but
 * offsets in the PDO mapping, because PDO entry indices may not be unique
 * inside a slave's PDO mapping. An error is raised, if
 * one of the given positions is out of range.
 *类似于ecrt从站配置reg pdo entry()，但不使用pdo索引，而是在pdo映射中使用偏移量，
 因为pdo条目索引可能不是唯一的“在一个从站的pdo映射中”。如果。将引发错误其中一个
 给定的位置超出了范围。
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \retval >=0 Success: Offset of the PDO entry's process data.
 * \retval  <0 Error code.
 */
int ecrt_slave_config_reg_pdo_entry_pos(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint8_t sync_index, /**< Sync manager index. */
        unsigned int pdo_pos, /**< Position of the PDO inside the SM.在同步管理器中PDO的位置 */
        unsigned int entry_pos, /**< Position of the entry inside the PDO. 在PDO中条目中位置*/
        ec_domain_t *domain, /**< Domain. */
        unsigned int *bit_position /**< Optional address if bit addressing
                                 is desired如果需要位寻址，可选地址 */
        );

/**10 Configure distributed clocks.
 *配置分布式时钟
 * Sets the AssignActivate word and the cycle and shift times for the sync
 * signals.
 *为同义词信号设置AssignActivate单词和周期和移位时间。
 * The AssignActivate word is vendor-specific and can be taken from the XML
 * device description file (Device -> Dc -> AssignActivate). Set this to zero,
 * if the slave shall be operated without distributed clocks (default).
 *
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \attention The \a sync1_shift time is ignored.
 */
void ecrt_slave_config_dc(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint16_t assign_activate, /**< AssignActivate word.分配激活字词0x300,清能伺服 */
        uint32_t sync0_cycle, /**< SYNC0 cycle time [ns]. */
        int32_t sync0_shift, /**< SYNC0 shift time [ns]. */
        uint32_t sync1_cycle, /**< SYNC1 cycle time [ns]. */
        int32_t sync1_shift /**< SYNC1 shift time [ns]. */
        );

/**11 Add an SDO configuration.
 *添加sDo配置。
 * An SDO configuration is stored in the slave configuration object and is
 * downloaded to the slave whenever the slave is being configured by the
 * master. This usually happens once on master activation, but can be repeated
 * subsequently, for example after the slave's power supply failed.
 *sDo配置存储在从配置对象中，并在主服务器配置从配置时下载到从配置。这通常在主激
 活时发生一次，但可以在随后重复，例如在从电源失败后。
 * \attention The SDOs for PDO assignment (\p 0x1C10 - \p 0x1C2F) and PDO
 * mapping (\p 0x1600 - \p 0x17FF and \p 0x1A00 - \p 0x1BFF) should not be
 * configured with this function, because they are part of the slave
 * configuration done by the master. Please use ecrt_slave_config_pdos() and
 * friends instead.
 *
 * This is the generic function for adding an SDO configuration. Please note
 * that the this function does not do any endianness correction. If
 * datatype-specific functions are needed (that automatically correct the
 * endianness), have a look at ecrt_slave_config_sdo8(),
 * ecrt_slave_config_sdo16() and ecrt_slave_config_sdo32().
 *
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_slave_config_sdo(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint16_t index, /**< Index of the SDO to configure. */
        uint8_t subindex, /**< Subindex of the SDO to configure. */
        const uint8_t *data, /**< Pointer to the data. */
        size_t size /**< Size of the \a data. */
        );

/**12 Add a configuration value for an 8-bit SDO.
 *添加一个8位sDo的配置值。
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *这个方法必须在非实时环境中在ecrt master activate()之前被调用。
 * \see ecrt_slave_config_sdo().
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_slave_config_sdo8(
        ec_slave_config_t *sc, /**< Slave configuration */
        uint16_t sdo_index, /**< Index of the SDO to configure. */
        uint8_t sdo_subindex, /**< Subindex of the SDO to configure. */
        uint8_t value /**< Value to set. */
        );

/**13 Add a configuration value for a 16-bit SDO.
 *
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \see ecrt_slave_config_sdo().
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_slave_config_sdo16(
        ec_slave_config_t *sc, /**< Slave configuration */
        uint16_t sdo_index, /**< Index of the SDO to configure. */
        uint8_t sdo_subindex, /**< Subindex of the SDO to configure. */
        uint16_t value /**< Value to set. */
        );

/**14 Add a configuration value for a 32-bit SDO.
 *
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \see ecrt_slave_config_sdo().
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_slave_config_sdo32(
        ec_slave_config_t *sc, /**< Slave configuration */
        uint16_t sdo_index, /**< Index of the SDO to configure. */
        uint8_t sdo_subindex, /**< Subindex of the SDO to configure. */
        uint32_t value /**< Value to set. */
        );

/**15 Add configuration data for a complete SDO.
 *
 * The SDO data are transferred via CompleteAccess. Data for the first
 * subindex (0) have to be included.
 *
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \see ecrt_slave_config_sdo().
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_slave_config_complete_sdo(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint16_t index, /**< Index of the SDO to configure. */
        const uint8_t *data, /**< Pointer to the data. */
        size_t size /**< Size of the \a data. */
        );

/**16 Set the size of the CoE emergency ring buffer.
 *
 * The initial size is zero, so all messages will be dropped. This method can
 * be called even after master activation, but it will clear the ring buffer!
 *
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \return 0 on success, or negative error code.
 */
int ecrt_slave_config_emerg_size(
        ec_slave_config_t *sc, /**< Slave configuration. */
        size_t elements /**< Number of records of the CoE emergency ring. */
        );

/**17 Read and remove one record from the CoE emergency ring buffer.
 *
 * A record consists of 8 bytes:
 *
 * Byte 0-1: Error code (little endian)
 * Byte   2: Error register
 * Byte 3-7: Data
 *
 * \return 0 on success (record popped), or negative error code (i. e.
 * -ENOENT, if ring is empty).
 */
int ecrt_slave_config_emerg_pop(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint8_t *target /**< Pointer to target memory (at least
                          EC_COE_EMERGENCY_MSG_SIZE bytes). */
        );

/**18 Clears CoE emergency ring buffer and the overrun counter.
 *
 * \return 0 on success, or negative error code.
 */
int ecrt_slave_config_emerg_clear(
        ec_slave_config_t *sc /**< Slave configuration. */
        );

/**19 Read the number of CoE emergency overruns.
 *
 * The overrun counter will be incremented when a CoE emergency message could
 * not be stored in the ring buffer and had to be dropped. Call
 * ecrt_slave_config_emerg_clear() to reset the counter.
 *
 * \return Number of overruns since last clear, or negative error code.
 */
int ecrt_slave_config_emerg_overruns(
        ec_slave_config_t *sc /**< Slave configuration. */
        );

/**20 Create an SDO request to exchange SDOs during realtime operation.
 *创建一个sDo请求以在实时操作期间交换sDo。
 * The created SDO request object is freed automatically when the master is
 * released.
 *创建的sDo请求对象在master释放时自动释放。
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \return New SDO request, or NULL on error.
 */
ec_sdo_request_t *ecrt_slave_config_create_sdo_request(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint16_t index, /**< SDO index. */
        uint8_t subindex, /**< SDO subindex. */
        size_t size /**< Data size to reserve. */
        );

/**21 Create an VoE handler to exchange vendor-specific data during realtime
 * operation.
 *
 * The number of VoE handlers per slave configuration is not limited, but
 * usually it is enough to create one for sending and one for receiving, if
 * both can be done simultaneously.
 *
 * The created VoE handler object is freed automatically when the master is
 * released.
 *
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \return New VoE handler, or NULL on error.
 */
ec_voe_handler_t *ecrt_slave_config_create_voe_handler(
        ec_slave_config_t *sc, /**< Slave configuration. */
        size_t size /**< Data size to reserve. */
        );

/**22 Create a register request to exchange EtherCAT register contents during
 * realtime operation.
 *
 * This interface should not be used to take over master functionality,
 * instead it is intended for debugging and monitoring reasons.
 *
 * The created register request object is freed automatically when the master
 * is released.
 *
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \return New register request, or NULL on error.
 */
ec_reg_request_t *ecrt_slave_config_create_reg_request(
        ec_slave_config_t *sc, /**< Slave configuration. */
        size_t size /**< Data size to reserve. */
        );

/**23 Outputs the state of the slave configuration.
 *输出从站的配置状态。
 * Stores the state information in the given \a state structure. The state
 * information is updated by the master state machine, so it may take a few
 * cycles, until it changes.
 *
 * \attention If the state of process data exchange shall be monitored in
 * realtime, ecrt_domain_state() should be used.
 */
void ecrt_slave_config_state(
        const ec_slave_config_t *sc, /**< Slave configuration 从站配置*/
        ec_slave_config_state_t *state /**< State object to write to. 要写的状态对象*/
        );

/**24 Add an SoE IDN configuration.
 *
 * A configuration for a Sercos-over-EtherCAT IDN is stored in the slave
 * configuration object and is written to the slave whenever the slave is
 * being configured by the master. This usually happens once on master
 * activation, but can be repeated subsequently, for example after the slave's
 * power supply failed.
 *Sercos-over-EtherCAT IDN的配置被存储在从端配置对象中，
 并且在主端配置从端时被写入到从端。这通常在主激活时发生一次，但可以在随后重复，
 例如在从电源失败后。
 * The \a idn parameter can be separated into several sections:
 *  - Bit 15: Standard data (0) or Product data (1)
 *  - Bit 14 - 12: Parameter set (0 - 7)
 *  - Bit 11 - 0: Data block number (0 - 4095)
 *
 * Please note that the this function does not do any endianness correction.
 * Multi-byte data have to be passed in EtherCAT endianness (little-endian).
 *请注意，这个函数不做任何端序更正。“多字节数据必须以EtherCAT字节顺序(little-endian)传递。”
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *
 * \retval  0 Success.
 * \retval <0 Error code.
 */
int ecrt_slave_config_idn(
        ec_slave_config_t *sc, /**< Slave configuration. */
        uint8_t drive_no, /**< Drive number. */
        uint16_t idn, /**< SoE IDN. */
        ec_al_state_t state, /**< AL state in which to write the IDN (PREOP or
                               SAFEOP). */
        const uint8_t *data, /**< Pointer to the data. */
        size_t size /**< Size of the \a data. */
        );

/******************************************************************************
 *07 Domain methods 域操作方法
 *****************************************************************************/

/**01 Registers a bunch of PDO entries for a domain.
 *为一个域注册一堆PDO条目。
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *这个方法必须在非实时环境中在ecrt master activate()之前被调用。
 * \see ecrt_slave_config_reg_pdo_entry()
 *
 * \attention The registration array has to be terminated with an empty
 *            structure, or one with the \a index field set to zero!
 *注意：注册数组必须以一个空结构结束，或者一个\a index字段设置为零!
 * \return 0 on success, else non-zero.0成功，其他非0
 */
int ecrt_domain_reg_pdo_entry_list(
        ec_domain_t *domain, /**< Domain. 域*/
        const ec_pdo_entry_reg_t *pdo_entry_regs /**< Array of PDO
                                                   registrations.PDO注册数组 */
        );

/**02 Returns the current size of the domain's process data.
 *返回域进程数据的当前大小。
 * \return Size of the process data image, or a negative error code.
 */
size_t ecrt_domain_size(
        const ec_domain_t *domain /**< Domain. */
        );

#ifdef __KERNEL__

/**03 Provide external memory to store the domain's process data.
 *提供外部内存来存储域的进程数据。
 * Call this after all PDO entries have been registered and before activating
 * the master.
 *在所有PDO条目都被注册之后，在激活主站之前调用这个函数。
 * The size of the allocated memory must be at least ecrt_domain_size(), after
 * all PDO entries have been registered.
 *在所有PDO条目都被注册之后，在激活主条目之前调用这个函数。
 * This method has to be called in non-realtime context before
 * ecrt_master_activate().
 *这个方法必须在非实时环境中在ecrt master activate()之前被调用。
 */
void ecrt_domain_external_memory(
        ec_domain_t *domain, /**< Domain. */
        uint8_t *memory /**< Address of the memory to store the process
                          data in. */
        );

#endif /* __KERNEL__ */

/**04 Returns the domain's process data.
 *返回域的进程数据。
 * - In kernel context: If external memory was provided with
 * ecrt_domain_external_memory(), the returned pointer will contain the
 * address of that memory. Otherwise it will point to the internally allocated
 * memory. In the latter case, this method may not be called before
 * ecrt_master_activate().
 *—在内核上下文中:如果提供了外部内存Ecrt域外部内存()，返回的指针将包含该内存的地址。
 否则，它将指向内部分配的内存。在后一种情况下，这个方法不能被调用在主站激活前。
 * - In userspace context: This method has to be called after
 * ecrt_master_activate() to get the mapped domain process data memory.
 *-In用户空间上下文:这个方法必须在之后调用'ecrt master activate()来获取映射的域进程数据内存。
 * \return Pointer to the process data memory.
 */
uint8_t *ecrt_domain_data(
        ec_domain_t *domain /**< Domain. */
        );

/**05 Determines the states of the domain's datagrams.
 *确定域数据报的状态。
 * Evaluates the working counters of the received datagrams and outputs
 * statistics, if necessary. This must be called after ecrt_master_receive()
 * is expected to receive the domain datagrams in order to make
 * ecrt_domain_state() return the result of the last process data exchange.
 评估接收到的数据报的工作计数器，并在必要时输出统计数据。这必须在ecrt master receive()
 接收域数据报之后调用，以便创建Ecrt域状态()返回最后一次进程数据交换的结果。
 */
void ecrt_domain_process(
        ec_domain_t *domain /**< Domain. */
        );

/**06 (Re-)queues all domain datagrams in the master's datagram queue.
 *在主站的数据报队列中队列所有域数据报。
 * Call this function to mark the domain's datagrams for exchanging at the
 * 调用这个函数来标记要交换的域数据报
 * next call of ecrt_master_send().
 */
void ecrt_domain_queue(
        ec_domain_t *domain /**< Domain. */
        );

/**07 Reads the state of a domain.
 *读取域状态
 * Stores the domain state in the given \a state structure.
 *
 * Using this method, the process data exchange can be monitored in realtime.
 */
void ecrt_domain_state(
        const ec_domain_t *domain, /**< Domain. */
        ec_domain_state_t *state /**< Pointer to a state object to store the
                                   information. */
        );

/*****************************************************************************
 *08 SDO request methods. SDO请求方法
 ****************************************************************************/

/**01 Set the SDO index and subindex.
 *
 * \attention If the SDO index and/or subindex is changed while
 * ecrt_sdo_request_state() returns EC_REQUEST_BUSY, this may lead to
 * unexpected results.
 */
void ecrt_sdo_request_index(
        ec_sdo_request_t *req, /**< SDO request. */
        uint16_t index, /**< SDO index. */
        uint8_t subindex /**< SDO subindex. */
        );

/**02 Set the timeout for an SDO request.
 *
 * If the request cannot be processed in the specified time, if will be marked
 * as failed.
 *
 * The timeout is permanently stored in the request object and is valid until
 * the next call of this method.
 */
void ecrt_sdo_request_timeout(
        ec_sdo_request_t *req, /**< SDO request. */
        uint32_t timeout /**< Timeout in milliseconds. Zero means no
                           timeout. */
        );

/**03 Access to the SDO request's data.
 *
 * This function returns a pointer to the request's internal SDO data memory.
 *这个函数返回一个指向请求内部sDo数据内存的指针。
 * - After a read operation was successful, integer data can be evaluated using
 *   the EC_READ_*() macros as usual. Example:
 *   \code
 *   uint16_t value = EC_READ_U16(ecrt_sdo_request_data(sdo)));
 *   \endcode
 * - If a write operation shall be triggered, the data have to be written to
 *   the internal memory. Use the EC_WRITE_*() macros, if you are writing
 *   integer data. Be sure, that the data fit into the memory. The memory size
 *   is a parameter of ecrt_slave_config_create_sdo_request().
 *   \code
 *   EC_WRITE_U16(ecrt_sdo_request_data(sdo), 0xFFFF);
 *   \endcode
 *
 * \attention The return value can be invalid during a read operation, because
 * the internal SDO data memory could be re-allocated if the read SDO data do
 * not fit inside.
 *
 * \return Pointer to the internal SDO data memory.
 */
uint8_t *ecrt_sdo_request_data(
        ec_sdo_request_t *req /**< SDO request. */
        );

/**04 Returns the current SDO data size.
 *
 * When the SDO request is created, the data size is set to the size of the
 * reserved memory. After a read operation the size is set to the size of the
 * read data. The size is not modified in any other situation.
 *
 * \return SDO data size in bytes.
 */
size_t ecrt_sdo_request_data_size(
        const ec_sdo_request_t *req /**< SDO request. */
        );

/**05 Get the current state of the SDO request.
 *
 * \return Request state.
 */
#ifdef __KERNEL__
ec_request_state_t ecrt_sdo_request_state(
        const ec_sdo_request_t *req /**< SDO request. */
    );
#else
ec_request_state_t ecrt_sdo_request_state(
        ec_sdo_request_t *req /**< SDO request. */
    );
#endif

/**06 Schedule an SDO write operation.
 *
 * \attention This method may not be called while ecrt_sdo_request_state()
 * returns EC_REQUEST_BUSY.
 */
void ecrt_sdo_request_write(
        ec_sdo_request_t *req /**< SDO request. */
        );

/**07 Schedule an SDO read operation.
 *
 * \attention This method may not be called while ecrt_sdo_request_state()
 * returns EC_REQUEST_BUSY.
 *
 * \attention After calling this function, the return value of
 * ecrt_sdo_request_data() must be considered as invalid while
 * ecrt_sdo_request_state() returns EC_REQUEST_BUSY.
 */
void ecrt_sdo_request_read(
        ec_sdo_request_t *req /**< SDO request. */
        );

/*****************************************************************************
 *09 VoE handler methods. VoE处理方法
 ****************************************************************************/

/**01 Sets the VoE header for future send operations.
 *
 * A VoE message shall contain a 4-byte vendor ID, followed by a 2-byte vendor
 * type at as header. These numbers can be set with this function. The values
 * are valid and will be used for future send operations until the next call
 * of this method.
 */
void ecrt_voe_handler_send_header(
        ec_voe_handler_t *voe, /**< VoE handler. */
        uint32_t vendor_id, /**< Vendor ID. */
        uint16_t vendor_type /**< Vendor-specific type. */
        );

/**02 Reads the header data of a received VoE message.
 *
 * This method can be used to get the received VoE header information after a
 * read operation has succeeded.
 *
 * The header information is stored at the memory given by the pointer
 * parameters.
 */
void ecrt_voe_handler_received_header(
        const ec_voe_handler_t *voe, /**< VoE handler. */
        uint32_t *vendor_id, /**< Vendor ID. */
        uint16_t *vendor_type /**< Vendor-specific type. */
        );

/**03 Access to the VoE handler's data.
 *
 * This function returns a pointer to the VoE handler's internal memory, that
 * points to the actual VoE data right after the VoE header (see
 * ecrt_voe_handler_send_header()).
 *
 * - After a read operation was successful, the memory contains the received
 *   data. The size of the received data can be determined via
 *   ecrt_voe_handler_data_size().
 * - Before a write operation is triggered, the data have to be written to the
 *   internal memory. Be sure, that the data fit into the memory. The reserved
 *   memory size is a parameter of ecrt_slave_config_create_voe_handler().
 *
 * \attention The returned pointer is not necessarily persistent: After a read
 * operation, the internal memory may have been reallocated. This can be
 * avoided by reserving enough memory via the \a size parameter of
 * ecrt_slave_config_create_voe_handler().
 *
 * \return Pointer to the internal memory.
 */
uint8_t *ecrt_voe_handler_data(
        ec_voe_handler_t *voe /**< VoE handler. */
        );

/**04 Returns the current data size.
 *
 * The data size is the size of the VoE data without the header (see
 * ecrt_voe_handler_send_header()).
 *
 * When the VoE handler is created, the data size is set to the size of the
 * reserved memory. At a write operation, the data size is set to the number
 * of bytes to write. After a read operation the size is set to the size of
 * the read data. The size is not modified in any other situation.
 *
 * \return Data size in bytes.
 */
size_t ecrt_voe_handler_data_size(
        const ec_voe_handler_t *voe /**< VoE handler. */
        );

/**05 Start a VoE write operation.
 *
 * After this function has been called, the ecrt_voe_handler_execute() method
 * must be called in every bus cycle as long as it returns EC_REQUEST_BUSY. No
 * other operation may be started while the handler is busy.
 */
void ecrt_voe_handler_write(
        ec_voe_handler_t *voe, /**< VoE handler. */
        size_t size /**< Number of bytes to write (without the VoE header). */
        );

/**06 Start a VoE read operation.
 *
 * After this function has been called, the ecrt_voe_handler_execute() method
 * must be called in every bus cycle as long as it returns EC_REQUEST_BUSY. No
 * other operation may be started while the handler is busy.
 *
 * The state machine queries the slave's send mailbox for new data to be send
 * to the master. If no data appear within the EC_VOE_RESPONSE_TIMEOUT
 * (defined in master/voe_handler.c), the operation fails.
 *
 * On success, the size of the read data can be determined via
 * ecrt_voe_handler_data_size(), while the VoE header of the received data
 * can be retrieved with ecrt_voe_handler_received_header().
 */
void ecrt_voe_handler_read(
        ec_voe_handler_t *voe /**< VoE handler. */
        );

/**07 Start a VoE read operation without querying the sync manager status.
 *
 * After this function has been called, the ecrt_voe_handler_execute() method
 * must be called in every bus cycle as long as it returns EC_REQUEST_BUSY. No
 * other operation may be started while the handler is busy.
 *
 * The state machine queries the slave by sending an empty mailbox. The slave
 * fills its data to the master in this mailbox. If no data appear within the
 * EC_VOE_RESPONSE_TIMEOUT (defined in master/voe_handler.c), the operation
 * fails.
 *
 * On success, the size of the read data can be determined via
 * ecrt_voe_handler_data_size(), while the VoE header of the received data
 * can be retrieved with ecrt_voe_handler_received_header().
 */
void ecrt_voe_handler_read_nosync(
        ec_voe_handler_t *voe /**< VoE handler. */
        );

/**08 Execute the handler.
 *
 * This method executes the VoE handler. It has to be called in every bus
 * cycle as long as it returns EC_REQUEST_BUSY.
 *
 * \return Handler state.
 */
ec_request_state_t ecrt_voe_handler_execute(
    ec_voe_handler_t *voe /**< VoE handler. */
    );

/*****************************************************************************
 *10 Register request methods.寄存器请求方法
 ****************************************************************************/

/**01 Access to the register request's data.
 *
 * This function returns a pointer to the request's internal memory.
 *
 * - After a read operation was successful, integer data can be evaluated
 *   using the EC_READ_*() macros as usual. Example:
 *   \code
 *   uint16_t value = EC_READ_U16(ecrt_reg_request_data(reg_request)));
 *   \endcode
 * - If a write operation shall be triggered, the data have to be written to
 *   the internal memory. Use the EC_WRITE_*() macros, if you are writing
 *   integer data. Be sure, that the data fit into the memory. The memory size
 *   is a parameter of ecrt_slave_config_create_reg_request().
 *   \code
 *   EC_WRITE_U16(ecrt_reg_request_data(reg_request), 0xFFFF);
 *   \endcode
 *
 * \return Pointer to the internal memory.
 */
uint8_t *ecrt_reg_request_data(
        ec_reg_request_t *req /**< Register request. */
        );

/** Get the current state of the register request.
 *
 * \return Request state.
 */
#ifdef __KERNEL__
ec_request_state_t ecrt_reg_request_state(
        const ec_reg_request_t *req /**< Register request. */
    );
#else
ec_request_state_t ecrt_reg_request_state(
        ec_reg_request_t *req /**< Register request. */
    );
#endif

/**02 Schedule an register write operation.
 *
 * \attention This method may not be called while ecrt_reg_request_state()
 * returns EC_REQUEST_BUSY.
 *
 * \attention The \a size parameter is truncated to the size given at request
 * creation.
 */
void ecrt_reg_request_write(
        ec_reg_request_t *req, /**< Register request. */
        uint16_t address, /**< Register address. */
        size_t size /**< Size to write. */
        );

/**03 Schedule a register read operation.
 *
 * \attention This method may not be called while ecrt_reg_request_state()
 * returns EC_REQUEST_BUSY.
 *
 * \attention The \a size parameter is truncated to the size given at request
 * creation.
 */
void ecrt_reg_request_read(
        ec_reg_request_t *req, /**< Register request. */
        uint16_t address, /**< Register address. */
        size_t size /**< Size to write. */
        );

/******************************************************************************
 *11 Bitwise read/write macros 位读/写宏
 *****************************************************************************/

/**01 Read a certain bit of an EtherCAT data byte.
 *
 * \param DATA EtherCAT data pointer
 * \param POS bit position
 */
#define EC_READ_BIT(DATA, POS) ((*((uint8_t *) (DATA)) >> (POS)) & 0x01)

/**02 Write a certain bit of an EtherCAT data byte.
 *
 * \param DATA EtherCAT data pointer
 * \param POS bit position
 * \param VAL new bit value
 */
#define EC_WRITE_BIT(DATA, POS, VAL) \
    do { \
        if (VAL) *((uint8_t *) (DATA)) |=  (1 << (POS)); \
        else     *((uint8_t *) (DATA)) &= ~(1 << (POS)); \
    } while (0)

/******************************************************************************
 *12 Byte-swapping functions for user space用户空间的字节交换函数
 *****************************************************************************/

#ifndef __KERNEL__

#if __BYTE_ORDER == __LITTLE_ENDIAN

#define le16_to_cpu(x) x
#define le32_to_cpu(x) x
#define le64_to_cpu(x) x

#define cpu_to_le16(x) x
#define cpu_to_le32(x) x
#define cpu_to_le64(x) x

#elif __BYTE_ORDER == __BIG_ENDIAN

#define swap16(x) \
        ((uint16_t)( \
        (((uint16_t)(x) & 0x00ffU) << 8) | \
        (((uint16_t)(x) & 0xff00U) >> 8) ))
#define swap32(x) \
        ((uint32_t)( \
        (((uint32_t)(x) & 0x000000ffUL) << 24) | \
        (((uint32_t)(x) & 0x0000ff00UL) <<  8) | \
        (((uint32_t)(x) & 0x00ff0000UL) >>  8) | \
        (((uint32_t)(x) & 0xff000000UL) >> 24) ))
#define swap64(x) \
        ((uint64_t)( \
        (((uint64_t)(x) & 0x00000000000000ffULL) << 56) | \
        (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
        (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
        (((uint64_t)(x) & 0x00000000ff000000ULL) <<  8) | \
        (((uint64_t)(x) & 0x000000ff00000000ULL) >>  8) | \
        (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
        (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
        (((uint64_t)(x) & 0xff00000000000000ULL) >> 56) ))

#define le16_to_cpu(x) swap16(x)
#define le32_to_cpu(x) swap32(x)
#define le64_to_cpu(x) swap64(x)

#define cpu_to_le16(x) swap16(x)
#define cpu_to_le32(x) swap32(x)
#define cpu_to_le64(x) swap64(x)

#endif

#define le16_to_cpup(x) le16_to_cpu(*((uint16_t *)(x)))
#define le32_to_cpup(x) le32_to_cpu(*((uint32_t *)(x)))
#define le64_to_cpup(x) le64_to_cpu(*((uint64_t *)(x)))

#endif /* ifndef __KERNEL__ */

/******************************************************************************
 *13 Read macros 读宏
 *****************************************************************************/

/** Read an 8-bit unsigned value from EtherCAT data.
 *
 * \return EtherCAT data value
 */
#define EC_READ_U8(DATA) \
    ((uint8_t) *((uint8_t *) (DATA)))

/** Read an 8-bit signed value from EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \return EtherCAT data value
 */
#define EC_READ_S8(DATA) \
     ((int8_t) *((uint8_t *) (DATA)))

/** Read a 16-bit unsigned value from EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \return EtherCAT data value
 */
#define EC_READ_U16(DATA) \
     ((uint16_t) le16_to_cpup((void *) (DATA)))

/** Read a 16-bit signed value from EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \return EtherCAT data value
 */
#define EC_READ_S16(DATA) \
     ((int16_t) le16_to_cpup((void *) (DATA)))

/** Read a 32-bit unsigned value from EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \return EtherCAT data value
 */
#define EC_READ_U32(DATA) \
     ((uint32_t) le32_to_cpup((void *) (DATA)))

/** Read a 32-bit signed value from EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \return EtherCAT data value
 */
#define EC_READ_S32(DATA) \
     ((int32_t) le32_to_cpup((void *) (DATA)))

/** Read a 64-bit unsigned value from EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \return EtherCAT data value
 */
#define EC_READ_U64(DATA) \
     ((uint64_t) le64_to_cpup((void *) (DATA)))

/** Read a 64-bit signed value from EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \return EtherCAT data value
 */
#define EC_READ_S64(DATA) \
     ((int64_t) le64_to_cpup((void *) (DATA)))

/******************************************************************************
 *14 Floating-point read functions and macros (userspace only)浮点读取函数和宏(仅限用户空间)
 *****************************************************************************/

#ifndef __KERNEL__

/** Read a 32-bit floating-point value from EtherCAT data.
 *
 * \param data EtherCAT data pointer
 * \return EtherCAT data value
 */
float ecrt_read_real(const void *data);

/** Read a 32-bit floating-point value from EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \return EtherCAT data value
 */
#define EC_READ_REAL(DATA) ecrt_read_real(DATA)

/** Read a 64-bit floating-point value from EtherCAT data.
 *
 * \param data EtherCAT data pointer
 * \return EtherCAT data value
 */
double ecrt_read_lreal(const void *data);

/** Read a 64-bit floating-point value from EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \return EtherCAT data value
 */
#define EC_READ_LREAL(DATA) ecrt_read_lreal(DATA)

#endif // ifndef __KERNEL__

/******************************************************************************
 *15 Write macros 写宏
 *****************************************************************************/

/** Write an 8-bit unsigned value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_U8(DATA, VAL) \
    do { \
        *((uint8_t *)(DATA)) = ((uint8_t) (VAL)); \
    } while (0)

/** Write an 8-bit signed value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_S8(DATA, VAL) EC_WRITE_U8(DATA, VAL)

/** Write a 16-bit unsigned value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_U16(DATA, VAL) \
    do { \
        *((uint16_t *) (DATA)) = cpu_to_le16((uint16_t) (VAL)); \
    } while (0)

/** Write a 16-bit signed value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_S16(DATA, VAL) EC_WRITE_U16(DATA, VAL)

/** Write a 32-bit unsigned value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_U32(DATA, VAL) \
    do { \
        *((uint32_t *) (DATA)) = cpu_to_le32((uint32_t) (VAL)); \
    } while (0)

/** Write a 32-bit signed value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_S32(DATA, VAL) EC_WRITE_U32(DATA, VAL)

/** Write a 64-bit unsigned value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_U64(DATA, VAL) \
    do { \
        *((uint64_t *) (DATA)) = cpu_to_le64((uint64_t) (VAL)); \
    } while (0)

/** Write a 64-bit signed value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_S64(DATA, VAL) EC_WRITE_U64(DATA, VAL)

/******************************************************************************
 *16 Floating-point write functions and macros (userspace only)浮点写函数和宏(仅限用户空间)
 *****************************************************************************/

#ifndef __KERNEL__

/** Write a 32-bit floating-point value to EtherCAT data.
 *
 * \param data EtherCAT data pointer
 * \param value new value
 */
void ecrt_write_real(void *data, float value);

/** Write a 32-bit floating-point value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_REAL(DATA, VAL) ecrt_write_real(DATA, VAL)

/** Write a 64-bit floating-point value to EtherCAT data.
 *
 * \param data EtherCAT data pointer
 * \param value new value
 */
void ecrt_write_lreal(void *data, double value);

/** Write a 64-bit floating-point value to EtherCAT data.
 *
 * \param DATA EtherCAT data pointer
 * \param VAL new value
 */
#define EC_WRITE_LREAL(DATA, VAL) ecrt_write_lreal(DATA, VAL)

#endif // ifndef __KERNEL__

/*****************************************************************************/

#ifdef __cplusplus
}
#endif

/*****************************************************************************/

/** @} */

#endif
